home *** CD-ROM | disk | FTP | other *** search
- /* Generic scrollbar implementation.
- Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
- Copyright (C) 1995 Amdahl Corporation.
- Copyright (C) 1995 Sun Microsystems.
- Copyright (C) 1995 Darrell Kindred <dkindred+@cmu.edu>.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Not in FSF. */
-
- /* This file has been Mule-ized. */
-
- #include <config.h>
- #include "lisp.h"
-
- #include "buffer.h"
- #include "commands.h"
- #include "scrollbar.h"
- #include "device.h"
- #include "frame.h"
- #include "window.h"
-
- Lisp_Object Qinit_scrollbar_from_resources;
-
- Lisp_Object Qscrollbar_line_up;
- Lisp_Object Qscrollbar_line_down;
- Lisp_Object Qscrollbar_page_up;
- Lisp_Object Qscrollbar_page_down;
- Lisp_Object Qscrollbar_to_top;
- Lisp_Object Qscrollbar_to_bottom;
- Lisp_Object Qscrollbar_vertical_drag;
-
- Lisp_Object Qscrollbar_char_left;
- Lisp_Object Qscrollbar_char_right;
- Lisp_Object Qscrollbar_page_left;
- Lisp_Object Qscrollbar_page_right;
- Lisp_Object Qscrollbar_to_left;
- Lisp_Object Qscrollbar_to_right;
- Lisp_Object Qscrollbar_horizontal_drag;
-
- #define DEFAULT_SCROLLBAR_WIDTH 15
- #define DEFAULT_SCROLLBAR_HEIGHT 15
-
- /* Width of the scrollbar. */
- Lisp_Object Vscrollbar_width;
-
- /* Height of the scrollbar. */
- Lisp_Object Vscrollbar_height;
-
- static void update_scrollbar_instance (struct window *w, int vertical,
- struct scrollbar_instance *instance);
-
-
- static void
- free_scrollbar_instance (struct scrollbar_instance *instance,
- struct frame *frame)
- {
- if (!instance)
- return;
- else
- {
- struct device *d = XDEVICE (frame->device);
-
- MAYBE_DEVMETH (d, free_scrollbar_instance, (instance));
- }
- }
-
- static void
- free_window_mirror_scrollbars (struct window_mirror *mir)
- {
- struct frame *f = mir->frame;
- free_scrollbar_instance (mir->scrollbar_vertical_instance, f);
- mir->scrollbar_vertical_instance = 0;
- free_scrollbar_instance (mir->scrollbar_horizontal_instance, f);
- mir->scrollbar_horizontal_instance = 0;
- }
-
- static struct window_mirror *
- free_scrollbars_loop (Lisp_Object window, struct window_mirror *mir)
- {
- struct window_mirror *retval = NULL;
-
- while (mir)
- {
- struct scrollbar_instance *vinst = mir->scrollbar_vertical_instance;
- struct scrollbar_instance *hinst = mir->scrollbar_horizontal_instance;
- struct frame *f;
-
- assert (!NILP (window));
- f = XFRAME (XWINDOW (window)->frame);
-
- if (mir->vchild)
- {
- retval = free_scrollbars_loop (XWINDOW (window)->vchild,
- mir->vchild);
- }
- else if (mir->hchild)
- {
- retval = free_scrollbars_loop (XWINDOW (window)->hchild,
- mir->hchild);
- }
-
- if (retval != NULL)
- return retval;
-
- if (hinst || vinst)
- free_window_mirror_scrollbars (mir);
-
- mir = mir->next;
- window = XWINDOW (window)->next;
- }
-
- return NULL;
- }
-
- /* Destroy all scrollbars associated with FRAME. Only called from
- delete_frame_internal.
- */
- #define FREE_FRAME_SCROLLBARS_INTERNAL(cache) \
- do { \
- while (FRAME_SB_##cache (f)) \
- { \
- struct scrollbar_instance *tofree = FRAME_SB_##cache (f); \
- FRAME_SB_##cache (f) = FRAME_SB_##cache (f)->next; \
- tofree->next = NULL; \
- free_scrollbar_instance (tofree, f); \
- } \
- } while (0)
-
- void
- free_frame_scrollbars (struct frame *f)
- {
- struct device *d = XDEVICE (f->device);
-
- if (!HAS_DEVMETH_P (d, create_scrollbar_instance))
- return;
-
- if (f->mirror_dirty)
- update_frame_window_mirror (f);
-
- free_scrollbars_loop (f->root_window, f->root_mirror);
-
- FREE_FRAME_SCROLLBARS_INTERNAL (VCACHE);
- FREE_FRAME_SCROLLBARS_INTERNAL (HCACHE);
- }
- #undef FREE_FRAME_SCROLLBARS_INTERNAL
-
-
- static struct scrollbar_instance *
- create_scrollbar_instance (struct frame *f, int vertical)
- {
- struct device *d = XDEVICE (f->device);
- struct scrollbar_instance *instance =
- (struct scrollbar_instance *) xmalloc (sizeof (*instance));
-
- memset (instance, 0, sizeof (*instance));
- MAYBE_DEVMETH (d, create_scrollbar_instance, (f, vertical, instance));
-
- return instance;
- }
-
-
- #define GET_SCROLLBAR_INSTANCE_INTERNAL(cache) \
- do { \
- if (FRAME_SB_##cache (f)) \
- { \
- struct scrollbar_instance *retval = FRAME_SB_##cache (f); \
- FRAME_SB_##cache (f) = FRAME_SB_##cache (f)->next; \
- retval->next = NULL; \
- return retval; \
- } \
- } while (0)
-
- static struct scrollbar_instance *
- get_scrollbar_instance (struct frame *f, int vertical)
- {
- /* Check if there are any available scrollbars already in existence. */
- if (vertical)
- GET_SCROLLBAR_INSTANCE_INTERNAL (VCACHE);
- else
- GET_SCROLLBAR_INSTANCE_INTERNAL (HCACHE);
-
- return create_scrollbar_instance (f, vertical);
- }
- #undef GET_SCROLLBAR_INSTANCE_INTERNAL
-
- #define RELEASE_SCROLLBAR_INSTANCE_INTERNAL(cache) \
- do { \
- if (!FRAME_SB_##cache (f)) \
- { \
- instance->next = NULL; \
- FRAME_SB_##cache (f) = instance; \
- } \
- else \
- { \
- instance->next = FRAME_SB_##cache (f); \
- FRAME_SB_##cache (f) = instance; \
- } \
- } while (0)
-
- static void
- release_scrollbar_instance (struct frame *f, int vertical,
- struct scrollbar_instance *instance)
- {
- /* #### should we do "instance->mir = 0;" for safety? */
- if (vertical)
- RELEASE_SCROLLBAR_INSTANCE_INTERNAL (VCACHE);
- else
- RELEASE_SCROLLBAR_INSTANCE_INTERNAL (HCACHE);
- }
- #undef RELEASE_SCROLLBAR_INSTANCE_INTERNAL
-
- void
- update_window_scrollbars (struct window *w, struct window_mirror *mirror,
- int active, int horiz_only)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
-
- if (!HAS_DEVMETH_P (d, create_scrollbar_instance))
- return;
-
- in_display++;
-
- /* It is possible for this to get called from the mirror update
- routines. In that case the structure is in an indeterminate
- state but we know exactly what struct we are working with. So we
- pass it in in that case. We also take advantage of it at some
- other points where we know what the mirror struct is. */
- if (!mirror)
- mirror = find_window_mirror (w);
-
- if (!mirror->scrollbar_vertical_instance && active)
- mirror->scrollbar_vertical_instance = get_scrollbar_instance (f, 1);
-
- if (!mirror->scrollbar_horizontal_instance && active)
- mirror->scrollbar_horizontal_instance = get_scrollbar_instance (f, 0);
-
- if (!horiz_only && mirror->scrollbar_vertical_instance)
- {
- int size = (active ? window_scrollbar_width (w) : 0);
- struct scrollbar_instance *instance;
-
- instance = mirror->scrollbar_vertical_instance;
- instance->scrollbar_is_active = active;
- instance->mirror = mirror;
-
- if (active && size)
- update_scrollbar_instance (w, 1, instance);
- MAYBE_DEVMETH (d, update_scrollbar_instance_status,
- (w, active, size, instance));
-
- if (!active)
- {
- release_scrollbar_instance (f, 1, instance);
- mirror->scrollbar_vertical_instance = NULL;
- }
- }
-
- if (mirror->scrollbar_horizontal_instance)
- {
- int size = (active ? window_scrollbar_height (w) : 0);
- struct scrollbar_instance *instance;
-
- instance = mirror->scrollbar_horizontal_instance;
- instance->scrollbar_is_active = active;
- instance->mirror = mirror;
-
- if (active && size)
- update_scrollbar_instance (w, 0, instance);
- MAYBE_DEVMETH (d, update_scrollbar_instance_status,
- (w, active, size, instance));
-
- if (!active)
- {
- release_scrollbar_instance (f, 0, instance);
- mirror->scrollbar_horizontal_instance = NULL;
- }
- }
-
- in_display--;
- }
-
- void
- release_window_mirror_scrollbars (struct window_mirror *mir)
- {
- struct device *d = XDEVICE (mir->frame->device);
-
- if (!HAS_DEVMETH_P (d, create_scrollbar_instance))
- return;
-
- if (mir->scrollbar_vertical_instance)
- {
- release_scrollbar_instance (mir->frame, 1,
- mir->scrollbar_vertical_instance);
- MAYBE_DEVMETH (d, release_scrollbar_instance,
- (mir->scrollbar_vertical_instance));
- }
- mir->scrollbar_vertical_instance = 0;
-
- if (mir->scrollbar_horizontal_instance)
- {
- release_scrollbar_instance (mir->frame, 0,
- mir->scrollbar_horizontal_instance);
- MAYBE_DEVMETH (d, release_scrollbar_instance,
- (mir->scrollbar_horizontal_instance));
- }
- mir->scrollbar_horizontal_instance = 0;
- }
-
- /* This check needs to be done in the device-specific side. */
- #define UPDATE_DATA_FIELD(field, value) \
- if (instance->field != value) {\
- instance->field = value;\
- instance->scrollbar_instance_changed = 1;\
- }\
-
- /*
- * If w->sb_point is on the top line then return w->sb_point else
- * return w->start. If flag, then return beginning point of line
- * which w->sb_point lies on.
- */
- static Bufpos
- scrollbar_point (struct window *w, int flag)
- {
- Bufpos start_pos, end_pos, sb_pos;
- Lisp_Object buf;
- struct buffer *b;
-
- if (NILP (w->buffer)) /* non-leaf window */
- return 0;
-
- start_pos = marker_position (w->start[CURRENT_DISP]);
- sb_pos = marker_position (w->sb_point);
-
- if (!flag && sb_pos < start_pos)
- return start_pos;
-
- buf = get_buffer (w->buffer, 0);
- if (!NILP (buf))
- b = XBUFFER (buf);
- else
- return start_pos;
-
- if (flag)
- end_pos = find_next_newline_no_quit (b, sb_pos, -1);
- else
- end_pos = find_next_newline_no_quit (b, start_pos, 1);
-
- if (flag)
- return end_pos;
- else if (sb_pos > end_pos)
- return start_pos;
- else
- return sb_pos;
- }
-
- /*
- * Update a window's horizontal or vertical scrollbar.
- */
- static void
- update_scrollbar_instance (struct window *w, int vertical,
- struct scrollbar_instance *instance)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- struct buffer *b = XBUFFER (w->buffer);
- Bufpos start_pos, end_pos, sb_pos;
- int scrollbar_width = window_scrollbar_width (w);
- int scrollbar_height = window_scrollbar_height (w);
-
- int new_line_increment = -1, new_page_increment = -1;
- int new_minimum = -1, new_maximum = -1;
- int new_slider_size = -1, new_slider_position = -1;
- int new_width = -1, new_height = -1, new_x = -1, new_y = -1;
- struct window *new_window = 0; /* kludge city */
-
- end_pos = BUF_Z (b) - w->window_end_pos[CURRENT_DISP];
- sb_pos = scrollbar_point (w, 0);
- start_pos = sb_pos;
-
- /* The end position must be strictly greater than the start
- position, at least for the Motify scrollbar. It shouldn't hurt
- anything for other scrollbar implementations. */
- if (end_pos <= start_pos)
- end_pos = start_pos + 1;
-
- if (vertical)
- {
- new_height = WINDOW_TEXT_HEIGHT (w);
- new_width = scrollbar_width;
- }
- else
- {
- new_height = scrollbar_height;
- new_width = WINDOW_TEXT_WIDTH (w);
- }
-
- /* If the height and width are not greater than 0, then later on the
- Motif widgets will bitch and moan. */
- if (new_height <= 0)
- new_height = 1;
- if (new_width <= 0)
- new_width = 1;
-
- assert (instance->mirror && XWINDOW (real_window(instance->mirror, 0)) == w);
-
- /* Only character-based scrollbars are implemented at the moment.
- Line-based will be implemented in the future. */
-
- instance->scrollbar_is_active = 1;
- new_line_increment = 1;
- new_page_increment = 1;
-
- if (!DEVMETH_OR_GIVEN (d, inhibit_scrollbar_thumb_size_change, (), 0))
- {
- int x_offset, y_offset;
-
- /* Scrollbars are always the farthest from the text area. */
- if (vertical)
- {
- x_offset = (f->scrollbar_on_left
- ? WINDOW_LEFT (w)
- : WINDOW_RIGHT (w) - scrollbar_width);
- y_offset = WINDOW_TEXT_TOP (w) + f->scrollbar_y_offset;
- }
- else
- {
- x_offset = WINDOW_TEXT_LEFT (w);
- y_offset = f->scrollbar_y_offset +
- (f->scrollbar_on_top
- ? WINDOW_TOP (w)
- : WINDOW_TEXT_BOTTOM (w) + window_bottom_toolbar_height (w));
- }
-
- new_x = x_offset;
- new_y = y_offset;
- }
-
- /* A disabled scrollbar has its slider sized to the entire height of
- the scrollbar. Currently the minibuffer scrollbar is
- disabled. */
- if (!MINI_WINDOW_P (w) && vertical)
- {
- if (!DEVMETH_OR_GIVEN (d, inhibit_scrollbar_thumb_size_change, (), 0))
- {
- new_minimum = BUF_BEGV (b);
- new_maximum = max (BUF_ZV (b), new_minimum + 1);
- new_slider_size = min ((end_pos - start_pos),
- (new_maximum - new_minimum));
- new_slider_position = sb_pos;
- new_window = w;
- }
- }
- else if (!MINI_WINDOW_P (w))
- {
- /* The minus one is to account for the truncation glyph. */
- int wcw = window_char_width (w, 0) - 1;
- int max_width, max_slide;
-
- if (w->max_line_len < wcw)
- {
- max_width = 1;
- max_slide = 1;
- wcw = 1;
- }
- else
- {
- max_width = w->max_line_len + 2;
- max_slide = max_width - wcw;
- }
-
- new_minimum = 0;
- new_maximum = max_width;
- new_slider_size = wcw;
- new_slider_position = min (w->hscroll, max_slide);
- }
- else
- {
- new_minimum = 1;
- new_maximum = 2;
- new_slider_size = 1;
- new_slider_position = 1;
- instance->scrollbar_is_active = 0;
- }
-
- DEVMETH (d, update_scrollbar_instance_values, (w, instance,
- new_line_increment,
- new_page_increment,
- new_minimum,
- new_maximum,
- new_slider_size,
- new_slider_position,
- new_width, new_height,
- new_x, new_y));
- }
-
- void
- init_frame_scrollbars (struct frame *f)
- {
- struct device *d = XDEVICE (f->device);
-
- if (HAS_DEVMETH_P (d, create_scrollbar_instance))
- {
- Lisp_Object frame = Qnil;
-
- XSETFRAME (frame, f);
- call_critical_lisp_code (XDEVICE (FRAME_DEVICE (f)),
- Qinit_scrollbar_from_resources,
- frame);
- }
- }
-
- void
- init_device_scrollbars (struct device *d)
- {
- if (HAS_DEVMETH_P (d, create_scrollbar_instance))
- {
- Lisp_Object device = Qnil;
-
- XSETDEVICE (device, d);
- call_critical_lisp_code (d,
- Qinit_scrollbar_from_resources,
- device);
- }
- }
-
- void
- init_global_scrollbars (struct device *d)
- {
- if (HAS_DEVMETH_P (d, create_scrollbar_instance))
- {
- call_critical_lisp_code (d,
- Qinit_scrollbar_from_resources,
- Qglobal);
- }
- }
-
-
- /* This function is called as a result of a change to the
- `scrollbar-width' specifier. */
- static void
- scrollbar_width_changed_in_frame (Lisp_Object specifier, struct frame *f,
- Lisp_Object oldval)
- {
- struct device *d = XDEVICE (f->device);
-
- MAYBE_DEVMETH (d, scrollbar_width_changed_in_frame, (specifier, f, oldval));
- }
-
- /* This function is called as a result of a change to the
- `scrollbar-height' specifier. */
- static void
- scrollbar_height_changed_in_frame (Lisp_Object specifier, struct frame *f,
- Lisp_Object oldval)
- {
- struct device *d = XDEVICE (f->device);
-
- MAYBE_DEVMETH (d, scrollbar_height_changed_in_frame, (specifier, f, oldval));
- }
-
- /* ####
-
- All of the following stuff is functions that handle scrollbar
- actions. All of it should be moved into Lisp. This may require
- adding some badly-needed primitives. */
-
- /********** vertical scrollbar stuff **********/
-
- /*
- * If the original point is still visible, put the cursor back there.
- * Otherwise, when scrolling down stick it at the beginning of the
- * first visible line and when scrolling up stick it at the beginning
- * of the last visible line.
- */
-
- /* #### This function should be moved into Lisp */
- static void
- scrollbar_reset_cursor (Lisp_Object win, Lisp_Object orig_pt)
- {
- /* When this function is called we know that start is already
- accurate. We know this because either set-window-start or
- recenter was called immediately prior to it being called. */
- Lisp_Object buf;
- Bufpos start_pos = XINT (Fwindow_start (win));
- Bufpos ptint = XINT (orig_pt);
- struct window *w = XWINDOW (win);
- int selected = ((w == XWINDOW (Fselected_window (XFRAME (w->frame)->device)))
- ? 1
- : 0);
-
- buf = Fwindow_buffer (win);
- if (NILP (buf))
- return; /* the window was deleted out from under us */
-
- if (ptint < XINT (Fwindow_start (win)))
- {
- if (selected)
- Fgoto_char (make_number (start_pos), buf);
- else
- Fset_window_point (win, make_number (start_pos));
- }
- else if (!point_would_be_visible (XWINDOW (win), start_pos, ptint))
- {
- Fmove_to_window_line (make_number (-1), win);
-
- if (selected)
- Fbeginning_of_line (Qnil, buf);
- else
- {
- /* #### Taken from forward-line. */
- Bufpos pos;
-
- pos = find_next_newline (XBUFFER (buf),
- marker_position (w->pointm[CURRENT_DISP]),
- -1);
- Fset_window_point (win, make_number (pos));
- }
- }
- else
- {
- if (selected)
- Fgoto_char (orig_pt, buf);
- else
- Fset_window_point (win, orig_pt);
- }
- }
-
- DEFUN ("scrollbar-line-up", Fscrollbar_line_up, Sscrollbar_line_up, 1, 1, 0,
- "Function called when the line-up arrow on the scrollbar is clicked.\n\
- This is the little arrow at the top of the scrollbar. One argument, the\n\
- scrollbar's window. You can advise this function to change the scrollbar\n\
- behavior.")
- (window)
- Lisp_Object window;
- {
- CHECK_LIVE_WINDOW (window, 0);
- window_scroll (window, make_number (1), -1, 1);
- zmacs_region_stays = 1;
- return Qnil;
- }
-
- DEFUN ("scrollbar-line-down", Fscrollbar_line_down, Sscrollbar_line_down,
- 1, 1, 0,
- "Function called when the line-down arrow on the scrollbar is clicked.\n\
- This is the little arrow at the bottom of the scrollbar. One argument, the\n\
- scrollbar's window. You can advise this function to change the scrollbar\n\
- behavior.")
- (window)
- Lisp_Object window;
- {
- CHECK_LIVE_WINDOW (window, 0);
- window_scroll (window, make_number (1), 1, 1);
- zmacs_region_stays = 1;
- return Qnil;
- }
-
- DEFUN ("scrollbar-page-up", Fscrollbar_page_up, Sscrollbar_page_up,
- 1, 1, 0,
- "Function called when the user gives the \"page-up\" scrollbar action.\n\
- (The way this is done can vary from scrollbar to scrollbar.) One argument,\n\
- a cons containing the scrollbar's window and a value (#### document me!\n\
- This value is nil for Motif/Lucid scrollbars and a number for Athena\n\
- scrollbars). You can advise this function to change the scrollbar\n\
- behavior.")
- (object)
- Lisp_Object object;
- {
- Lisp_Object window = Fcar (object);
-
- CHECK_LIVE_WINDOW (window, 0);
- /* Motif and Athena scrollbars behave differently, but in accordance
- with their standard behaviors. It is not possible to hide the
- differences down in lwlib because knowledge of XEmacs buffer and
- cursor motion routines is necessary. */
- #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
- window_scroll (window, Qnil, -1, 1);
- #else /* Athena */
- {
- Bufpos bufpos;
- Lisp_Object value = Fcdr (object);
-
- CHECK_INT (value, 0);
- Fmove_to_window_line (Qzero, window);
- /* can't use Fvertical_motion() because it moves the buffer point
- rather than the window's point.
-
- #### It does? Why does it take a window argument then? */
- bufpos = vmotion (XWINDOW (window), XINT (Fwindow_point (window)),
- XINT (value), 0);
- Fset_window_point (window, make_number (bufpos));
- Frecenter (Qzero, window);
- }
- #endif /* Athena */
- zmacs_region_stays = 1;
- return Qnil;
- }
-
- DEFUN ("scrollbar-page-down", Fscrollbar_page_down, Sscrollbar_page_down,
- 1, 1, 0,
- "Function called when the user gives the \"page-down\" scrollbar action.\n\
- (The way this is done can vary from scrollbar to scrollbar.) One argument,\n\
- a cons containing the scrollbar's window and a value (#### document me!\n\
- This value is nil for Motif/Lucid scrollbars and a number for Athena\n\
- scrollbars). You can advise this function to change the scrollbar\n\
- behavior.")
- (object)
- Lisp_Object object;
- {
- Lisp_Object window = Fcar (object);
-
- CHECK_LIVE_WINDOW (window, 0);
- /* Motif and Athena scrollbars behave differently, but in accordance
- with their standard behaviors. It is not possible to hide the
- differences down in lwlib because knowledge of XEmacs buffer and
- cursor motion routines is necessary. */
- #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
- window_scroll (window, Qnil, 1, 1);
- #else /* Athena */
- {
- Lisp_Object value = Fcdr (object);
- CHECK_INT (value, 0);
- Fmove_to_window_line (value, window);
- Frecenter (Qzero, window);
- }
- #endif /* Athena */
- zmacs_region_stays = 1;
- return Qnil;
- }
-
- DEFUN ("scrollbar-to-top", Fscrollbar_to_top, Sscrollbar_to_top,
- 1, 1, 0,
- "Function called when the user gives the \"to-top\" scrollbar action.\n\
- (The way this is done can vary from scrollbar to scrollbar.). One argument,\n\
- the scrollbar's window. You can advise this function to change the\n\
- scrollbar behavior.")
- (window)
- Lisp_Object window;
- {
- Lisp_Object orig_pt;
-
- orig_pt = Fwindow_point (window);
- Fset_window_point (window, Fpoint_min (Fwindow_buffer (window)));
- Frecenter (Qzero, window);
- scrollbar_reset_cursor (window, orig_pt);
- zmacs_region_stays = 1;
- return Qnil;
- }
-
- DEFUN ("scrollbar-to-bottom", Fscrollbar_to_bottom, Sscrollbar_to_bottom,
- 1, 1, 0,
- "Function called when the user gives the \"to-bottom\" scrollbar action.\n\
- (The way this is done can vary from scrollbar to scrollbar.). One argument,\n\
- the scrollbar's window. You can advise this function to change the\n\
- scrollbar behavior.")
- (window)
- Lisp_Object window;
- {
- Lisp_Object orig_pt;
-
- orig_pt = Fwindow_point (window);
- Fset_window_point (window, Fpoint_max (Fwindow_buffer (window)));
- Frecenter (Qzero, window);
- scrollbar_reset_cursor (window, orig_pt);
- zmacs_region_stays = 1;
- return Qnil;
- }
-
- DEFUN ("scrollbar-vertical-drag", Fscrollbar_vertical_drag,
- Sscrollbar_vertical_drag, 1, 1, 0,
- "Function called when the user drags the vertical scrollbar thumb.\n\
- One argument, a cons containing the scrollbar's window and a value\n\
- (#### document me!). You can advise this function to change the\n\
- scrollbar behavior.")
- (object)
- Lisp_Object object;
- {
- Bufpos start_pos;
- Lisp_Object orig_pt;
- Lisp_Object window = Fcar (object);
- Lisp_Object value = Fcdr (object);
-
- orig_pt = Fwindow_point (window);
- Fset_marker (XWINDOW (window)->sb_point, value, Fwindow_buffer (window));
- start_pos = scrollbar_point (XWINDOW (window), 1);
- Fset_window_start (window, make_number (start_pos), Qnil);
- scrollbar_reset_cursor (window, orig_pt);
- zmacs_region_stays = 1;
- return Qnil;
- }
-
- DEFUN ("scrollbar-set-hscroll", Fscrollbar_set_hscroll, Sscrollbar_set_hscroll,
- 2, 2, 0,
- "Sets WINDOW's hscroll position to VALUE.\n\
- This ensures that VALUE is in the proper range for the horizontal scrollbar.")
- (window, value)
- Lisp_Object window, value;
- {
- struct window *w;
- int hscroll, wcw, max_len;
-
- CHECK_LIVE_WINDOW (window, 0);
- if (!EQ (value, Qmax))
- CHECK_INT (value, 0);
-
- w = XWINDOW (window);
- wcw = window_char_width (w, 0) - 1;
- max_len = w->max_line_len + 1;
-
- if (EQ (value, Qmax) || (XINT (value) > (max_len - wcw)))
- hscroll = max_len - wcw;
- else
- hscroll = XINT (value);
-
- /* Can't allow this out of set-window-hscroll's acceptable range. */
- if (hscroll < 0)
- hscroll = 0;
- else if (hscroll >= (1 << (SHORTBITS - 1)))
- hscroll = (1 << (SHORTBITS - 1)) - 1;
-
- if (hscroll != w->hscroll)
- Fset_window_hscroll (window, make_number (hscroll));
-
- return Qnil;
- }
-
-
- /************************************************************************/
- /* initialization */
- /************************************************************************/
-
- void
- syms_of_scrollbar (void)
- {
- defsymbol (&Qscrollbar_line_up, "scrollbar-line-up");
- defsymbol (&Qscrollbar_line_down, "scrollbar-line-down");
- defsymbol (&Qscrollbar_page_up, "scrollbar-page-up");
- defsymbol (&Qscrollbar_page_down, "scrollbar-page-down");
- defsymbol (&Qscrollbar_to_top, "scrollbar-to-top");
- defsymbol (&Qscrollbar_to_bottom, "scrollbar-to-bottom");
- defsymbol (&Qscrollbar_vertical_drag, "scrollbar-vertical-drag");
-
- defsymbol (&Qscrollbar_char_left, "scrollbar-char-left");
- defsymbol (&Qscrollbar_char_right, "scrollbar-char-right");
- defsymbol (&Qscrollbar_page_left, "scrollbar-page-left");
- defsymbol (&Qscrollbar_page_right, "scrollbar-page-right");
- defsymbol (&Qscrollbar_to_left, "scrollbar-to-left");
- defsymbol (&Qscrollbar_to_right, "scrollbar-to-right");
- defsymbol (&Qscrollbar_horizontal_drag, "scrollbar-horizontal-drag");
-
- defsymbol (&Qinit_scrollbar_from_resources, "init-scrollbar-from-resources");
-
- /* #### All these functions should be moved into Lisp.
- See comment above. */
- defsubr (&Sscrollbar_line_up);
- defsubr (&Sscrollbar_line_down);
- defsubr (&Sscrollbar_page_up);
- defsubr (&Sscrollbar_page_down);
- defsubr (&Sscrollbar_to_top);
- defsubr (&Sscrollbar_to_bottom);
- defsubr (&Sscrollbar_vertical_drag);
-
- defsubr (&Sscrollbar_set_hscroll);
- }
-
- void
- specifier_vars_of_scrollbar (void)
- {
- DEFVAR_SPECIFIER ("scrollbar-width", &Vscrollbar_width,
- "*Width of vertical scrollbars.\n\
- This is a specifier; use `set-specifier' to change it.");
- Vscrollbar_width = Fmake_specifier (Qnatnum);
- set_specifier_fallback
- (Vscrollbar_width,
- list1 (Fcons (Qnil, make_number (DEFAULT_SCROLLBAR_WIDTH))));
- set_specifier_caching (Vscrollbar_width,
- slot_offset (struct window,
- scrollbar_width),
- some_window_value_changed,
- slot_offset (struct frame,
- scrollbar_width),
- scrollbar_width_changed_in_frame);
-
- DEFVAR_SPECIFIER ("scrollbar-height", &Vscrollbar_height,
- "*Width of vertical scrollbars.\n\
- This is a specifier; use `set-specifier' to change it.");
- Vscrollbar_height = Fmake_specifier (Qnatnum);
- set_specifier_fallback
- (Vscrollbar_height,
- list1 (Fcons (Qnil, make_number (DEFAULT_SCROLLBAR_HEIGHT))));
- set_specifier_caching (Vscrollbar_height,
- slot_offset (struct window,
- scrollbar_height),
- some_window_value_changed,
- slot_offset (struct frame,
- scrollbar_height),
- scrollbar_height_changed_in_frame);
- }
-